package client.comm.commlib.base

import android.app.Application
import android.util.Log
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.viewModelScope
import androidx.paging.*
import client.comm.commlib.network.XxRetroHttp
import client.comm.commlib.network.IServer
import client.comm.commlib.network.data.JsonResult
import client.comm.commlib.network.data.PagingJsonResult
import client.comm.commlib.out_time
import client.comm.commlib.toast.toast
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.isActive
import kotlinx.coroutines.withContext
import retrofit2.Response

open class BaseAppViewModel(app: Application) : AndroidViewModel(app) {

    val iServer: IServer by lazy {
        XxRetroHttp.createApi<IServer>(IServer::class.java)
    }

    fun <T> hold(
        block: suspend () -> Response<JsonResult<T>>,
        before: (() -> Unit)? = null,
        success: ((t: JsonResult<T>?) -> Unit)? = null,
        err: (() -> Unit)? = null,
        complete: (() -> Unit)? = null,
    ) {

        if (viewModelScope.isActive) {
            viewModelScope.async {
                var response: Response<JsonResult<T>>? = null

                withContext(Dispatchers.Main) {
                    before?.invoke()
                }
                response = withContext(Dispatchers.IO) {
                    try {
                        out_time {
                            response = block?.invoke()
                        }
                    } catch (e: Exception) {
                        Log.e("e", e.message, e)
                    } finally {

                    }
                    response
                }

                withContext(Dispatchers.Main) {
                    complete?.invoke()
                    if (response != null && response!!.isSuccessful && response!!.body() != null) {
                        response?.body()?.let {
                            success?.invoke(it)
                            if (!it.isSuccess) {
                                toast(it.message, it.code)
                                err?.invoke()
                            }
                        }
                    } else {
                        err?.invoke()
                        toast("网络错误")
                        success?.invoke(JsonResult<T>().apply {
                            message = "网络错误"
                        })
                    }
                }
            }
        }

    }


    //分页加载
    fun <T : Any> pagingData(
        pageSize: Int = 10,
        hold: suspend (p: Int) -> PagingJsonResult<T>?
    ): Flow<PagingData<T>> {
        return Pager(
            config = PagingConfig(pageSize = pageSize),
            pagingSourceFactory = {
                object : PagingSource<Int, T>() {
                    override fun getRefreshKey(state: PagingState<Int, T>): Int? =
                        null

                    override suspend fun load(params: LoadParams<Int>): LoadResult<Int, T> {
                        return try {
                            val page = params.key ?: 1
                            val ret = hold.invoke(page)
                            if (ret != null) {
                                if (ret.isSuccess) {
                                    val list = ret.list as List<T>
                                    val pPage = if (page > 1) page - 1 else null
                                    val nextKey = if (list.size > 0) page + 1 else null
                                    LoadResult.Page(list, pPage, nextKey)
                                } else {
                                    toast(ret.message, if (ret.code == null) -1 else ret.code)
                                    LoadResult.Error(java.lang.Exception(ret.message))
                                }
                            } else
                                LoadResult.Error(java.lang.Exception("网络错误"))
                        } catch (e: java.lang.Exception) {
                            LoadResult.Error(e)
                        }
                    }
                }
            }
        ).flow
    }

    //分页加载
    fun <T : Any> pagingDataAuto(
        pageSize: Int = 10,
        hold: suspend (p: Int) -> PagingJsonResult<T>?
    ): Flow<PagingData<T>> {
        return Pager(
            config = PagingConfig(pageSize = pageSize),
            pagingSourceFactory = {
                object : PagingSource<Int, T>() {
                    override fun getRefreshKey(state: PagingState<Int, T>): Int? =
                        null

                    override suspend fun load(params: LoadParams<Int>): LoadResult<Int, T> {
                        return try {
                            val page = params.key ?: 1
                            val ret = withContext(Dispatchers.IO) {
                                hold.invoke(page)
                            }
                            if (ret != null) {
                                if (ret.isSuccess) {
                                    val list = ret.list as List<T>
                                    val pPage = if (page > 1) page - 1 else null
                                    val nextKey = if (list.size > 0) page + 1 else null
                                    LoadResult.Page(list, pPage, nextKey)
                                } else {
                                    toast(ret.message, if (ret.code == null) -1 else ret.code)
                                    LoadResult.Error(java.lang.Exception(ret.message))
                                }
                            } else
                                LoadResult.Error(java.lang.Exception("网络错误"))
                        } catch (e: java.lang.Exception) {
                            LoadResult.Error(e)
                        }
                    }
                }
            }
        ).flow
    }

}